home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / BDTOTAB.PAK / OWLTAB.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  17KB  |  575 lines

  1. // (C) Copyright 1996, Borland International
  2. //
  3. // Owltab.cpp - VDBT Ttable example
  4. /*******************************************************************************
  5. This example demonstrates how hook up to a database table and then
  6. navigate through it using the VDBT Ttable object.  The user can navigate
  7. through the table using the Main Menu items or via the keyboard. Only one
  8. record will be displayed at a time.
  9.  
  10.  
  11.     SETTING UP TO USE AN EVENT HANDLER
  12.  
  13.     Visual Database Tools uses event sources and event sinks (or
  14.     handlers) to encapsulate everything necessary for repsonding
  15.     to event.  The general     steps are:
  16.     1.  Identify the source that will be the source of the events
  17.          you wish to handle, in this particular example, TDataSource.  This is
  18.          done in the MainCreateMsg function.
  19.     2.  Define the event sink to handle the event.  This is done as part of
  20.          the EventHandler class.
  21.     3.  Connect the event sink to the event handler.  This is done as part of
  22.          The EventHandle constructor.
  23.     4.  Connect the event source to the event sink.  This is done in the
  24.          MainCreateMsg function.
  25.  
  26.  
  27. The BIOLIFE table in the diveplan database is used by default.  A different
  28. database and table can be specified on as command line arguments.
  29.  
  30. The files needed to build this program are:
  31.  
  32. owltab.cpp            Source file for application
  33. owltab.rc            Resource file for application
  34. owltab.ico            Icon file for application
  35. owltab16/32.def    def file for 16bit target and 32bit target respectively
  36. makefile                command-line build file
  37. owltab.ide            BCW 5.0 project file for both the 16bit and 32bit target
  38.  
  39. *******************************************************************************/
  40.  
  41. #include <vdbt\bdto.h>
  42. #include <windowsx.h>
  43. #include "resource.h"
  44.  
  45. //******************************************************************************
  46.  
  47. #define NOTUSED( x )        ((void)(long) (x))
  48.  
  49. #define DATABASENAME "DivePlan"
  50. #define TABLENAME "biolife.db"
  51.  
  52. #define MAIN_CLASS_NAME    "Main Class"
  53.  
  54. //******************************************************************************
  55. // function prototypes
  56.  
  57. BOOL RegisterMainClass( HINSTANCE hInstance );
  58.  
  59. HWND CreateMainWindow( HINSTANCE hInstance, LPSTR lpszCmdLine, int cmdShow );
  60.  
  61. extern "C" LRESULT CALLBACK _export MainWndProc( HWND hwnd, UINT msg,
  62.                                                                 WPARAM wParam, LPARAM lParam );
  63.                                                 
  64. void MainCreateMsg( HWND hwnd, LPSTR lpszCmdLine );
  65.  
  66. void MainPaintMsg( HWND hwnd );
  67.  
  68. void GetAndDrawGraphic( HDC hdc, TGraphicField& graphic, int x, int y,
  69.                                                                                     int w, int h );
  70.                                                                
  71. void GetAndDisplayMemo( HDC hdc, TMemoField& memo,int top, int width,
  72.                                                                                         int height );
  73.                                                                   
  74. void DrawPrettyText( HDC hdc, string PrintString, int left, int top, int width,
  75.                                                                                         int height );
  76.                                                                   
  77. BOOL MainCommandMsg( HWND hwnd, WPARAM wParam, LPARAM lParam );
  78.  
  79. void MainKeyDownMsg( HWND hwnd, WPARAM wParam );
  80.  
  81. void MainDestroyMsg( HWND hwnd );
  82.  
  83.  
  84. #define EXTRA sizeof(TTable*) + sizeof(TDataSource*) + sizeof(EventHandler*)
  85. #define SWL_TABLE 0
  86. #define SWL_DATASOURCE 4
  87. #define SWL_EVENTHANDLER 8
  88.  
  89.  
  90. /*******************************************************************************
  91. EventHandler
  92.     This is the class that will handle the events that are generated
  93.     by the TDataSource object.  OnDataChangeSink is the sink for the
  94.     OnDataChangeEvent and the OnDataChange method will process all
  95.     events passed to OnDataChangeSink by the TDataSource
  96.     OnDataChangeSource object.
  97. *******************************************************************************/
  98.  
  99. class EventHandler
  100. {
  101. private:
  102.     HWND hwnd;
  103. public:
  104.     EventHandler( HWND h );
  105.     // define the event sink to handle the event.  This is step #2 of
  106.     // setting up to use an event handler for a VDBT event.
  107.     TDataChangeSink OnDataChangeSink;
  108. protected:
  109.     void OnDataChange(TDataChangeSink& sink, TDataSource& sender, TField* field);
  110. };
  111. // the OnDataChangeSink constructor connects OnDataChangeSink with the
  112. // event handler OnDataChange.  This performs stepd #3 for setting up
  113. // to use an event handler for a VDBT event.
  114. EventHandler::EventHandler( HWND h ):
  115.   OnDataChangeSink( TDataChange_MFUNCTOR( *this, &EventHandler::OnDataChange ) )
  116. {
  117.     hwnd = h;
  118. }
  119.  
  120. /*******************************************************************************
  121. OnDataChange
  122.   When the data changes (the user has navigated to a new record)
  123.   invalidate the right hand side of the window and force a repaint.
  124.   The left hand side of the windows does not need to be repainted
  125.   because it holds data the is static the entire time the app is
  126.   running.
  127. *******************************************************************************/
  128. void EventHandler::OnDataChange( TDataChangeSink&, TDataSource&, TField* )
  129. {
  130.     if (hwnd)
  131.     {
  132.         RECT rc;
  133.         GetClientRect( hwnd, &rc );
  134.         rc.left = rc.right/2;
  135.         InvalidateRect( hwnd, &rc, TRUE );
  136.     }
  137. }
  138.  
  139. //******************************************************************************
  140.  
  141. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
  142.                             LPSTR lpszCmdLine, int cmdShow )
  143. {
  144.     if (! hPrevInstance)
  145.         if (! RegisterMainClass(hInstance))
  146.             return 0;
  147.  
  148.     CreateMainWindow(hInstance, lpszCmdLine, cmdShow);
  149.  
  150.     MSG msg;
  151.     while (GetMessage(&msg, (HWND) 0, 0, 0))
  152.     {
  153.         TranslateMessage(&msg);
  154.         DispatchMessage(&msg);
  155.     }
  156.  
  157.     return 0;
  158. }
  159.  
  160. //******************************************************************************
  161.  
  162. BOOL RegisterMainClass( HINSTANCE hInstance )
  163. {
  164.     WNDCLASS wndClass;
  165.  
  166.     wndClass.style = CS_HREDRAW | CS_VREDRAW;
  167.     wndClass.lpfnWndProc = MainWndProc;
  168.     wndClass.cbClsExtra = 0;
  169.     // allocate extra memor to hold the table, datasource and event handler
  170.     // pointers.
  171.     wndClass.cbWndExtra = EXTRA;
  172.     wndClass.hInstance = hInstance;
  173.     wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
  174.     wndClass.hCursor = LoadCursor((HINSTANCE) 0, IDC_ARROW);
  175.     wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
  176.     wndClass.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN);
  177.     wndClass.lpszClassName = MAIN_CLASS_NAME;
  178.  
  179.     return RegisterClass(&wndClass);
  180. }
  181.  
  182. //******************************************************************************
  183.  
  184. HWND CreateMainWindow( HINSTANCE hInstance, LPSTR lpszCmdLine, int cmdShow )
  185. {
  186.     char    szTitle[30 + 1];
  187.     HWND    hwnd;
  188.  
  189.     LoadString(hInstance, IDS_MAINTITLE, szTitle, 30);
  190.     hwnd = CreateWindow(MAIN_CLASS_NAME, szTitle, WS_TILEDWINDOW,
  191.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  192.         (HWND) 0, (HMENU) 0, hInstance, lpszCmdLine);
  193.  
  194.     if (hwnd)
  195.     {
  196.         ShowWindow(hwnd, cmdShow);
  197.         UpdateWindow(hwnd);
  198.     }
  199.  
  200.     return hwnd;
  201. }
  202.  
  203. //******************************************************************************
  204.  
  205. extern "C" LRESULT CALLBACK _export MainWndProc(HWND hwnd, UINT msg,
  206.                                                                     WPARAM wParam, LPARAM lParam)
  207. {
  208.     switch (msg)
  209.     {
  210.         case WM_CREATE:
  211.             MainCreateMsg( hwnd, (LPSTR)((LPCREATESTRUCT) lParam)->lpCreateParams);
  212.             break;
  213.  
  214.         case WM_PAINT:
  215.             MainPaintMsg(hwnd);
  216.             break;
  217.  
  218.         case WM_COMMAND:
  219.             if (! MainCommandMsg(hwnd, wParam, lParam))
  220.                 return DefWindowProc(hwnd, msg, wParam, lParam);
  221.             break;
  222.  
  223.         case WM_KEYDOWN:
  224.             MainKeyDownMsg(hwnd, wParam);
  225.             break;
  226.  
  227.         case WM_DESTROY:
  228.             MainDestroyMsg(hwnd);
  229.             PostQuitMessage(0);
  230.             break;
  231.  
  232.         default:
  233.             return DefWindowProc(hwnd, msg, wParam, lParam);
  234.     }
  235.  
  236.     return 0L;
  237. }
  238.  
  239. /*******************************************************************************
  240.     MainCreateMsg.
  241.         This initializes the main window and the database table.  Things
  242.         to note are the create of the TTable object, the try block that
  243.         opens the database table, the create of the datasource object
  244.         and the attachment to the OnDataChange event.
  245. *******************************************************************************/
  246.  
  247. void MainCreateMsg(HWND hwnd, LPSTR lpszCmdLine)
  248. {
  249.     // Parse the command line for the alias and table names.
  250.  
  251.     LPSTR databaseName = DATABASENAME;
  252.     LPSTR tableName = TABLENAME;
  253.     if (*lpszCmdLine)
  254.     {
  255.         LPSTR space = strchr( lpszCmdLine, ' ');
  256.         if (space)
  257.         {
  258.             *space = '\0';
  259.             tableName = space+1;
  260.             databaseName = lpszCmdLine;
  261.         }
  262.     }
  263.  
  264.     // Update the window's title bar with the database and table names.
  265.  
  266.     char    szTitle[30 + 100 + 1];
  267.     int len = GetWindowText( hwnd, szTitle, sizeof(szTitle) );
  268.     wsprintf( szTitle+len, " - :%s:%s", databaseName, tableName );
  269.     SetWindowText( hwnd, szTitle );
  270.  
  271.     // Create the TTable object.  This is the step #1 for setting up to use
  272.     // an event handler for a VDBT event.
  273.  
  274.     TTable* table = new TTable;
  275.     if (table)
  276.     {
  277.         // Put the database and table name properties, open the table.
  278.  
  279.         try
  280.         {
  281.             table->DatabaseName = string( databaseName );
  282.             table->TableName = string( tableName );
  283.             table->Open();
  284.         }
  285.         catch (BDTException e)
  286.         {
  287.             e.Show( "processing WM_CREATE" );
  288.             delete table;
  289.             table = NULL;
  290.         }
  291.         // put the pointer to the table object to the 0 offset (SWL_TABLE=0) of
  292.       // the extra window memory of hwnd.
  293.         SetWindowLong( hwnd, SWL_TABLE, (LONG) table );
  294.  
  295.         if (table)
  296.         {
  297.             // Create a datasource object and attach to the OnDataChange event.
  298.  
  299.             EventHandler* handler = new EventHandler( hwnd );
  300.             if (handler)
  301.             {
  302.                 TDataSource* datasource = new TDataSource;
  303.                 if (datasource)
  304.                 {
  305.                     datasource->DataSet = table;
  306.                     // The following line connects the event source,
  307.                     // datasource->OnDataChangeSource to the event sink,
  308.                     // handler->OnDataChangeSink.  The is the fourth and final step
  309.                     // for setting up to use an event handler for a VDBT event.
  310.  
  311.                     datasource->OnDataChangeSource += handler->OnDataChangeSink;
  312.  
  313.  
  314.                     // put the pointer to the datasource object to the 4 offset
  315.                     // (SWL_DATASOURCE=4) of the extra window memory of hwnd.
  316.                     SetWindowLong( hwnd, SWL_DATASOURCE, (LONG) datasource );
  317.                 }
  318.                 // put the pointer to the event handler object to the 8 offset
  319.                 // (SWL_EVENTHANDLER=8) of the extra window memory of hwnd.
  320.                 SetWindowLong( hwnd, SWL_EVENTHANDLER, (LONG) handler );
  321.             }
  322.         }
  323.     }
  324. }
  325.  
  326.  
  327. /*******************************************************************************
  328. MainPaintMsg
  329.     This function will repaint the window with the (static) table field
  330.     names on the left side and the (dynamic) field entries on the right.
  331. *******************************************************************************/
  332.  
  333. void MainPaintMsg(HWND hwnd)
  334. {
  335.     PAINTSTRUCT ps;
  336.     RECT rc;
  337.  
  338.     BeginPaint( hwnd, &ps );
  339.     GetClientRect( hwnd, &rc );
  340.  
  341.     // Retrieve the pointer to the table from the extra memory in hwnd
  342.     TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
  343.  
  344.     
  345.     if (table)
  346.     {
  347.         int count = table->FieldCount;
  348.         if (count)
  349.         {
  350.             int width = rc.right/2;
  351.             int height = rc.bottom/count;
  352.  
  353.             // Paint the field names on the left side of the window, the
  354.             // field values on the right side of the window.
  355.  
  356.             int i;
  357.             for (i = 0; i < count; i++)
  358.             {
  359.                 string s = table->Fields[i]->FieldName;
  360.                 DrawPrettyText( ps.hdc, s, 0, i*height, width, height );
  361.  
  362.                 if (table->Fields[i]->DataType == ftGraphic)
  363.                 {
  364.                     GetAndDrawGraphic( ps.hdc, TGraphicField(table->Fields[i]),
  365.                                                    width, i*height, width, height );
  366.                 }
  367.                 else if (table->Fields[i]->DataType ==ftMemo)
  368.             {
  369.                     GetAndDisplayMemo( ps.hdc, TMemoField(table->Fields[i]),
  370.                                                                i*height, width, height );
  371.             }
  372.             else
  373.                 {
  374.                     s = table->Fields[i]->Text;
  375.                     DrawPrettyText( ps.hdc, s, width, i*height, width, height );
  376.                 }
  377.             }
  378.         }
  379.     }
  380.  
  381.     EndPaint(hwnd, &ps);
  382. }
  383.  
  384. /*******************************************************************************
  385. GetAndDrawGraphic
  386.     This will function will accurately display a graphic field that is
  387.     in the current record.   Note that the SaveToBitmap method will
  388.     save the bitmap from the graphic field to the hbitmap and hpalette
  389.     handles.  
  390. *******************************************************************************/
  391.  
  392. void GetAndDrawGraphic( HDC hdc, TGraphicField& graphic, int x, int y, int w,
  393.                                 int h )
  394. {
  395.     // Use the SaveToBitmap method to get the bitmap and palette handles.
  396.  
  397.     HBITMAP hbm = 0;
  398.     HPALETTE hpal = 0;
  399.     graphic.SaveToBitmap( hbm, hpal );
  400.     if (hbm)
  401.     {
  402.         HDC hdcTemp = CreateCompatibleDC( hdc );
  403.         if (hdcTemp)
  404.         {
  405.             BITMAP bm;
  406.             GetObject( hbm, sizeof(BITMAP), &bm );
  407.             HBITMAP hbmPrev = SelectBitmap( hdcTemp, hbm );
  408.             StretchBlt( hdc, x, y, w, h,
  409.                             hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
  410.             SelectBitmap( hdcTemp, hbmPrev );
  411.             DeleteDC( hdcTemp );
  412.         }
  413.         DeleteBitmap( hbm );
  414.     }
  415.     if (hpal)
  416.         DeletePalette( hpal );
  417. }
  418.  
  419.  
  420. /*******************************************************************************
  421. GetAndDisplayMemo
  422.     This function will accurately display a memo field that is
  423.     in the current record.   Note that the DrawPrettyText function will
  424.    perform word-wrap so that as much of the memo as possible will be
  425.    displayed.
  426. *******************************************************************************/
  427. void GetAndDisplayMemo( HDC hdc, TMemoField& memo, int top, int width,
  428.                                 int height)
  429. {
  430.     TMemoryStream stream;
  431.     memo.SaveToStream( stream );
  432.     stream.Position = 0;
  433.     TStrings strings;
  434.     strings.LoadFromStream( stream );
  435.     string s = strings.Text;
  436.    DrawPrettyText( hdc, s, width, top, width, height );
  437. }
  438.  
  439.  
  440.  
  441. /*******************************************************************************
  442. DrawPrettyText
  443. function will use DrawText to perform word-wrap so that as much of 
  444. text to be displayed as possible is actually displayed in the available
  445. rectangle.
  446. *******************************************************************************/
  447. void DrawPrettyText( HDC hdc, string PrintString, int left, int top, int width,
  448.                             int height )
  449. {
  450.     RECT rc;
  451.     rc.left = left;
  452.     rc.top = top;
  453.     rc.right = rc.left + width;
  454.     rc.bottom = rc.top + height;
  455.     DrawText(hdc, PrintString.c_str(), PrintString.length(), &rc,
  456.                DT_TOP | DT_LEFT | DT_WORDBREAK | DT_NOPREFIX );
  457. }
  458.  
  459. /*******************************************************************************
  460. MainCommandMsg
  461.     This handles all of the commands that come for the Main Menu
  462.     to navigate through the table. All other WM_COMMAND messages are
  463.     passed onto Windows.
  464. *******************************************************************************/
  465.  
  466. BOOL MainCommandMsg(HWND hwnd, WPARAM wParam, LPARAM lParam)
  467. {
  468.     NOTUSED( lParam );
  469.     // Process navigation commands from the menu.
  470.  
  471.     TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
  472.     if (table)
  473.     {
  474.         switch (GET_WM_COMMAND_ID(wParam, lParam))
  475.         {
  476.             case IDM_NAV_FIRST:
  477.                 table->First();
  478.                 break;
  479.             case IDM_NAV_PRIORSET:
  480.                 table->MoveBy(-5);
  481.                 break;
  482.             case IDM_NAV_PRIOR:
  483.                 table->Prior();
  484.                 break;
  485.             case IDM_NAV_NEXT:
  486.                 table->Next();
  487.                 break;
  488.             case IDM_NAV_NEXTSET:
  489.                 table->MoveBy(5);
  490.                 break;
  491.             case IDM_NAV_LAST:
  492.                 table->Last();
  493.                 break;
  494.             default:
  495.                 return FALSE;
  496.         }
  497.  
  498.         return TRUE;
  499.     }
  500.  
  501.     return FALSE;
  502. }
  503.  
  504.  
  505. /*******************************************************************************
  506. MainKeyDownMsg
  507.     This handle all of the keyboard messages that will be used to navigate
  508.     the table.  All other WM_KEYDOWN messages are passed onto Windows.
  509. *******************************************************************************/
  510.  
  511. void MainKeyDownMsg(HWND hwnd, WPARAM wParam)
  512. {
  513.     // Process navigation commands from the keyboard.
  514.  
  515.     TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
  516.     if (table)
  517.     {
  518.         switch (wParam)
  519.         {
  520.             case VK_HOME:
  521.                 table->First();
  522.                 break;
  523.             case VK_PRIOR:
  524.                 table->MoveBy(-5);
  525.                 break;
  526.             case VK_UP:
  527.                 table->Prior();
  528.                 break;
  529.             case VK_DOWN:
  530.                 table->Next();
  531.                 break;
  532.             case VK_NEXT:
  533.                 table->MoveBy(5);
  534.                 break;
  535.             case VK_END:
  536.                 table->Last();
  537.                 break;
  538.         }
  539.     }
  540. }
  541.  
  542.  
  543. /*******************************************************************************
  544. MainDestroyMsg
  545.     This destroys the datasource object, the handler object and then the
  546.     table object.
  547. *******************************************************************************/
  548.  
  549. void MainDestroyMsg( HWND hwnd )
  550. {
  551.     // Delete the table and the datasource.
  552.  
  553.     // Retrieve the pointer to the table from the extra memory in hwnd
  554.     // and then clear the entry.
  555.     TTable* table = (TTable*) GetWindowLong( hwnd, SWL_TABLE );
  556.     SetWindowLong( hwnd, SWL_TABLE, 0 );
  557.     if (table)
  558.     {
  559.         // Retrieve the pointer to the datasource from the extra memory in hwnd
  560.         // and then clear the entry.
  561.         TDataSource* datasource=(TDataSource*)GetWindowLong(hwnd, SWL_DATASOURCE);
  562.         SetWindowLong( hwnd, SWL_DATASOURCE, 0 );
  563.         if (datasource)
  564.             delete datasource;
  565.  
  566.         // Retrieve the pointer to the event handler from the extra memory
  567.         // in hwnd and then clear the entry.
  568.         EventHandler* handler=(EventHandler*)GetWindowLong(hwnd, SWL_EVENTHANDLER);
  569.         SetWindowLong( hwnd, SWL_EVENTHANDLER, 0 );
  570.         if (handler)
  571.             delete handler;
  572.  
  573.         delete table;
  574.    }
  575. }